/*
  * 
  * @ProjectName:    react-ts-app-test
  * @Package:        
  * @ClassName:      MemoCallback
  * @Description:    JSX文件 
  * @Author:         SuPeiSen
  * @CreateDate:     2021/8/13 10:13 上午
  * @UpdateDate:     2021/8/13 10:13 上午
  * @UpdateRemark:   更新说明：
  * @Version:        1.0
 */

import {RouteComponentProps} from "react-router-dom"
import {memo, useCallback, useMemo, useState} from "react";

/**
 * useMemo和useCallback对比页面
 * @param props
 * @constructor
 */
const MemoCallback = (props: RouteComponentProps) => {

    // 使用useState创建一个Array<string>类型的数据存储以及派发更新
    const [wzHeroList, setWzHeroList] = useState<Array<string>>(['虞姬', '鲁班', '狄仁杰'])
    // 模拟刷新
    const [count, setCount] = useState<number>(0)
    // 用于useCallback的依赖
    const [id, setId] = useState<number>(0)

    // 我们知道无状态组件的更新是从头到尾的更新，
    // 如果你想要从新渲染一部分视图，而不是整个组件，
    // 那么用useMemo是最佳方案，避免了不需要的更新，
    // useMemo的第一个参数为一个闭包，第二个参数是一个deps数组
    // 数组里的参数变化决定了useMemo是否更新回调函数
    const WzHeroList = useMemo(() => {
        console.log('【第二个参数不为空】HeroList组件触发render')
        return (
            <ul>
                {wzHeroList.map((item) => {
                    return <li key={item}>{item}</li>
                })}
            </ul>
        )
    }, [wzHeroList])

    // useMemo会缓存之前的state值
    // 如果没有加相关的更新条件，是获取不到更新之后的state的值的,
    const SecondParamIsEmpty = useMemo(() => {
        console.log('【第二个参数为空数组】HeroList组件触发render')
        return (
            <ul>
                {wzHeroList.map((item) => {
                    return <li key={item}>{item}</li>
                })}
            </ul>
        )
    }, [])
    // 当useMemo第二个参数传入了一个空数组后，ESLint会报错如下
    // ESLint: React Hook useMemo has a missing dependency: 'wzHeroList'.
    // Either include it or remove the dependency array.(react-hooks/exhaustive-deps)


    // useCallback第一个参数传入一个函数，第二个参数传入一个数组
    // useCallback返回的是函数, 在其依赖项发生变化后才执行
    const currentId = useCallback(()=>id, [id])

    return (
        <div>
            <h1>useMemo和useCallback区别</h1>
            <h2>王者荣耀</h2>
            {WzHeroList}
            {SecondParamIsEmpty}
            <h2>count value:{count}</h2>
            <button onClick={() => {
                console.log('触发刷新')
                setCount(count + 1)
            }}>刷新
            </button>
            <button onClick={() => {
                // 第一种方式
                setWzHeroList([...wzHeroList, '公孙离'])
            }}>添加英雄
            </button>
            <button onClick={() => {
                // 第一种方式
                setId(id+1);
            }}>id自增
            </button>
            <MemoCallbackChildMemo count={count} />
            <MemoCallbackChildNoMemo count={count} />
            <MemoCallbackChildMemoCallback id={currentId()} />
        </div>
    )
}

/**
 * 表示MemoCallback的子组件, 使用React.memo
 * @param props
 * @constructor
 */
const MemoCallbackChildMemo = memo((props: {count: number})=>{
    console.log('【MemoCallbackChildMemo】触发 render')
    return (
        <h3>子组件MemoCallbackChildMemo值：{props.count}</h3>
    )
})

/**
 * 表示MemoCallback的子组件, 不使用React.memo
 * @param props
 * @constructor
 */
const MemoCallbackChildNoMemo = (props: {count: number})=>{
    console.log('【MemoCallbackChildNoMemo】触发 render')
    return (
        <h3>子组件MemoCallbackChildNoMemo值：{props.count}</h3>
    )
}

/**
 * 表示MemoCallback的子组件,使用React.memo,
 * @param props
 * @constructor
 */
const MemoCallbackChildMemoCallback = memo((props: {id: number})=>{
    console.log('【MemoCallbackChildMemoCallback】触发 render')
    return (
        <h3>子组件MemoCallbackChildMemoCallback值：{props.id}</h3>
    )
})

export default MemoCallback